package fr.lille1.wordcount.service.impl;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import fr.lille1.wordcount.service.IWordCountService;
import fr.lille1.wordcount.util.Constants;

/**
 * Classe de service metier pour le wordcount
 * @author RAKOTOBE Sitraka Eric
 */
public class WordCountServiceImpl implements IWordCountService {


    
    /** 
     * Methode privee retournant une map des occurences de chacun des mots 
     * appartenant au tableau en parametre
     * @param tabWord : le tableau de mots dont on voudra les occurences
     * @return map contenant pour chaque mot son occurence dans un texte
     **/    
    private Map<String, Integer> getMapWordCountFromArray (String[] tabWord){
        Map<String, Integer> result = new HashMap<String, Integer>();
        for (int i = 0; i < tabWord.length; i++) {
            String word = tabWord[i];
            if (result.containsKey(word)){
                int cptWord = result.get(word) + 1; 
                result.put(word, cptWord);
            }else {
                result.put(word, 1);
            }
        }
        return result ;         
    }
    
    
    
    /** 
     * Methode privee permettant de trier une map par sa valeur decroissante
     * @param mapToSort : la map a trier
     * @return la map triee par valeur decroissante
     **/    
    private Map<String, Integer> getSortedMapByValueDesc(Map<String, Integer> mapToSort){
        List<Object> list = new LinkedList<Object>(mapToSort.entrySet());
        Collections.sort(list, new Comparator<Object>() {
            public int compare(Object o1, Object o2) {
                return (-1) * ((Comparable) ((Map.Entry) (o1)).getValue()).compareTo(((Map.Entry) (o2)).getValue());
            }
        });
        Map<String, Integer> result = new LinkedHashMap<String, Integer>();
        for (Iterator<Object> it = list.iterator(); it.hasNext();) {
            Map.Entry<String, Integer> entry = (Map.Entry<String, Integer>) it.next();
            result.put(entry.getKey().toString(), (Integer) entry.getValue());
        }
        return result ;         
    }    
    
    
    /** 
     * Methode privee permettant de trier une map par sa valeur decroissante
     * @param stringToTransform : la chaine de caractere a transformer en liste
     * @return la map triee par valeur decroissante
     **/    
    private List<String> buildListFromString(String stringToTransform){
    	String[] tabStringValue = stringToTransform.split(Constants.DELIMITER);
    	for (int i = 0; i < tabStringValue.length; i++) {
			tabStringValue[i] = tabStringValue[i].trim();
		}
    	return Arrays.asList(tabStringValue);      
    }  
    
    
    
    
    /** {@inheritDoc}**/
    public Map<String, Integer> countAllWordInText(String text) {
        String[] tabWord = text.split(Constants.SPACE_WORD);
        return getMapWordCountFromArray(tabWord);
    }

    
    
    /** {@inheritDoc}**/
    public Map<String, Integer> countAllWordInUrl(String urlPath){
        try {
            FileInputStream stream = new FileInputStream(new File(urlPath));
            FileChannel fc = stream.getChannel();
            MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
            String contentOfFile = Charset.defaultCharset().decode(bb).toString();
            String[] tabWord = contentOfFile.split(Constants.SPACE_WORD);
            stream.close();
            return getMapWordCountFromArray(tabWord);
        } catch (FileNotFoundException e){
            return null ;
        } catch (IOException e ){
            return null ;
        }
    }
    


    /** {@inheritDoc}**/
    public int countOneWordInText(String word, String text) {
        int cpt = 0 ;
        String[] tabWord = text.split(Constants.SPACE_WORD);
        for (int i = 0; i < tabWord.length; i++) {
            if (tabWord[i].equalsIgnoreCase(word)){
                cpt ++ ; 
            }
        }
        return cpt ;
    }
    
    


    /** {@inheritDoc}**/
    public int countOneWordInUrl(String word, String urlPath) {
        int cpt = 0 ; 
        try {
            FileInputStream stream = new FileInputStream(new File(urlPath));
            FileChannel fc = stream.getChannel();
            MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
            String contentOfFile = Charset.defaultCharset().decode(bb).toString();
            String[] tabWord = contentOfFile.split(Constants.SPACE_WORD);
            for (int i = 0; i < tabWord.length; i++) {
                if (tabWord[i].equalsIgnoreCase(word)){
                    cpt ++ ; 
                }
            }
            stream.close();
            return cpt ; 
        } catch (FileNotFoundException e){
            return 0 ;
        } catch (IOException e ){
            return 0 ;
        }
    }

    
    

    /** {@inheritDoc}**/
    public boolean isWordInText(String word, String text) {
        String[] tabWord = text.split(Constants.SPACE_WORD);
        for (int i = 0; i < tabWord.length; i++) {
            String wordFromArray = tabWord[i];
            if (wordFromArray.equalsIgnoreCase(word)){
                return true ; 
            }
        }        
        return false ; 
    }

    
    

    /** {@inheritDoc}**/
    public List<String> getAllFrequentWordsInText(String text, String stringValueOfList, int n) {
        List<String> result = new ArrayList<String>();
        List<String> words = buildListFromString(stringValueOfList);
        int cptForCountFrequencies = 0 ; 
        String[] tabWord = text.split(Constants.SPACE_WORD);
        Map<String, Integer> mapOfWordCount = getMapWordCountFromArray(tabWord);        
        Map<String, Integer> sortedMap = getSortedMapByValueDesc(mapOfWordCount);
        for (String keyOfSortedMap : sortedMap.keySet()) {
            if (!words.contains(keyOfSortedMap) && cptForCountFrequencies < n){
                result.add(keyOfSortedMap);
                cptForCountFrequencies ++ ;
            }
        }
        return result;
    }
    
}